Imports System.Drawing.Drawing2D
Imports System.Drawing

Public Module DrawingFunctions

    Public Function DistPointToLine(ByVal hitPtx As Single, ByVal hitPty As Single, ByVal hitPtz As Single, _
    ByVal TLX1 As Single, ByVal TLY1 As Single, ByVal TLZ1 As Single, ByVal vecXTarg As Single, _
    ByVal vecYTarg As Single, ByVal vecZTarg As Single, ByRef blnOutOfRange As Boolean) As Single

        '\\ By MSM: Nov 17, 2003 (Function designed to return the distance from a point to a line)
        '\\ (A . V) = (ax * vx) + (ay * vy) + (az * vz)
        '\\ cos(theta) = |A'|/|A|
        '\\ |A'| = (A . V)/|V| ...... calculates the length of the projected vector
        '\\ |A - A'| = Sqrt(|A|^2 - |A'|^2)
        '\\ pythagorean (a^2 + b^2)^.5 = c
        '\\ theta = acos(|A'|/|A|)

        Dim TLX2 As Single
        Dim TLY2 As Single
        Dim TLZ2 As Single

        Dim ax As Single
        Dim ay As Single
        Dim az As Single

        Dim ax_norm As Single
        Dim ay_norm As Single
        Dim az_norm As Single

        Dim vx2_norm As Single
        Dim vy2_norm As Single
        Dim vz2_norm As Single

        Dim len_a_squared As Single
        Dim a_dot_v As Single
        Dim a_dot_v_norm As Single
        Dim len_v As Single
        Dim a_dot_v_over_len_v As Double
        Dim len_a As Single

        Dim ptHitPt As New Point
        Dim ptLineStart As New Point
        Dim ptLineEnd As New Point

        Dim m As Single
        Dim mPerp As Single

        ptHitPt.X = hitPtx
        ptHitPt.Y = hitPty
        ptLineStart.X = TLX1
        ptLineStart.Y = TLY1

        TLX2 = TLX1 + vecXTarg
        TLY2 = TLY1 + vecYTarg
        TLZ2 = TLZ1 + vecZTarg
        ptLineEnd.X = TLX2
        ptLineEnd.Y = TLY2

        ax = hitPtx - TLX1
        ay = hitPty - TLY1
        az = hitPtz - TLZ1

        m = vecXTarg / vecYTarg

        If m <> 0 Then
            mPerp = -(1 / m)
        End If

        len_a = Math.Sqrt(ax * ax + ay * ay + az + az)
        ax_norm = ax / len_a : ay_norm = ay / len_a : az_norm = az / len_a

        len_a_squared = (ax * ax + ay * ay + az + az)

        a_dot_v = (ax * vecXTarg) + (ay * vecYTarg) + (az * vecZTarg)

        len_v = Math.Sqrt(vecXTarg * vecXTarg + vecYTarg * vecYTarg + vecZTarg * vecZTarg)
        vx2_norm = vecXTarg / len_v : vy2_norm = vecYTarg / len_v : vz2_norm = vecZTarg / len_v
        a_dot_v_norm = (ax_norm * vx2_norm) + (ay_norm * vy2_norm) + (az_norm * vz2_norm)

        '\\ given the two points and the hitpoint, determine if the hitpoint falls within the range
        If IsPtWithinRange(ptHitPt, ptLineStart, ptLineEnd) Then
            blnOutOfRange = False
        Else
            blnOutOfRange = True
        End If

        a_dot_v_over_len_v = a_dot_v / len_v

        Return (CSng(System.Math.Sqrt( _
            len_a_squared - (CSng(a_dot_v_over_len_v) ^ 2))))

    End Function

    Friend Function IsPtWithinRange(ByVal ptHit As Point, ByVal ptLSt As Point, ByVal ptLEnd As Point) As Boolean
        Dim m As Single
        Dim mPerp As Single
        Dim yEqSt As Single
        Dim yEqEnd As Single

        'y-y1 = mPerp * (x-x1) : point-slope line equation
        'y = (mPerp * x) - (mPerp * x1) + y1
        'm = dy/dx

        If (ptLEnd.Y - ptLSt.Y) <> 0 Then
            Select Case (ptLEnd.X - ptLSt.X)
                Case Is = 0
                    mPerp = 0
                    If (ptLEnd.Y > ptLSt.Y) Then
                        If (ptHit.Y > ptLSt.Y) And (ptHit.Y < ptLEnd.Y) Then
                            Return True
                        Else
                            Return False
                        End If
                    Else
                        If (ptHit.Y > ptLEnd.Y) And (ptHit.Y < ptLSt.Y) Then
                            Return True
                        Else
                            Return False
                        End If

                    End If
                Case Is > 0
                    m = (ptLEnd.Y - ptLSt.Y) / (ptLEnd.X - ptLSt.X)
                    mPerp = -(1 / m)
                    yEqSt = (mPerp * ptHit.X) - (mPerp * ptLSt.X) + ptLSt.Y
                    yEqEnd = (mPerp * ptHit.X) - (mPerp * ptLEnd.X) + ptLEnd.Y
                    If yEqSt > yEqEnd Then
                        If ptHit.Y > yEqEnd And ptHit.Y < yEqSt Then
                            Return True
                        Else
                            Return False
                        End If
                    Else
                        If ptHit.Y > yEqSt And ptHit.Y < yEqEnd Then
                            Return True
                        Else
                            Return False
                        End If
                    End If

                Case Is < 0
                    m = (ptLEnd.Y - ptLSt.Y) / (ptLEnd.X - ptLSt.X)
                    mPerp = -(1 / m)
                    yEqSt = (mPerp * ptHit.X) - (mPerp * ptLSt.X) + ptLSt.Y
                    yEqEnd = (mPerp * ptHit.X) - (mPerp * ptLEnd.X) + ptLEnd.Y
                    If yEqSt > yEqEnd Then
                        If ptHit.Y > yEqEnd And ptHit.Y < yEqSt Then
                            Return True
                        Else
                            Return False
                        End If
                    Else
                        If ptHit.Y > yEqSt And ptHit.Y < yEqEnd Then
                            Return True
                        Else
                            Return False
                        End If
                    End If
            End Select
        Else
            'dy = 0
            If (ptLSt.X > ptLEnd.X) Then
                If (ptHit.X > ptLEnd.X) And (ptHit.X < ptLSt.X) Then
                    Return True
                Else
                    Return False
                End If
            Else
                If (ptHit.X > ptLSt.X) And (ptHit.X < ptLEnd.X) Then
                    Return True
                Else
                    Return False
                End If
            End If
        End If

    End Function

End Module

Public Class DXFPoints

    Private m_points As New PointsClass
    Private m_p As PathData

    Public Property points() As PointsClass
        Get
            Return m_points
        End Get
        Set(ByVal Value As PointsClass)
            m_points = Value
        End Set
    End Property
    Public Sub DrawSegment(ByRef g As Graphics, ByVal pt1 As Point, ByVal pt2 As Point)

        Dim gpath As New GraphicsPath

        gpath.AddLine(pt1, pt2)
        Dim pe As Pen = New Pen(Color.Salmon, 4)
        pe.Color = Color.Salmon
        g.DrawPath(pe, gpath)
        g.Dispose()

    End Sub
    Public Sub Draw(ByRef g As Graphics)

        g.Clear(Color.Black)
        Dim gpath As New GraphicsPath

        Dim i As Integer
        Dim ar As Array = m_points.AsArray

        For i = 0 To ar.GetUpperBound(0)
            If i < 1 Then

            Else
                gpath.AddLine(ar(i - 1), ar(i))
            End If
        Next

        Dim pe As Pen = New Pen(Color.Blue, 1)
        pe.Color = Color.Blue
        g.DrawPath(pe, gpath)
        g.Dispose()

    End Sub

End Class

Public Class PointsClass
    Inherits System.Collections.CollectionBase
    Private m_LastPt As Point

    Public Function AsArray() As Array
        Return innerlist.ToArray
    End Function
    Public Property LastPt() As Point
        Get
            Return m_LastPt
        End Get
        Set(ByVal Value As Point)
            m_LastPt = Value
        End Set
    End Property
    Default Property Item(ByVal index As Integer) As Point
        Get
            Return innerlist.Item(index)
        End Get
        Set(ByVal Value As Point)
            innerlist.Item(index) = Value
        End Set
    End Property

    Public Sub Add(ByRef p As Point)
        Me.LastPt = p
        innerlist.Add(p)
    End Sub

    Public Sub remove(ByVal p As Point)
        innerlist.Remove(p)
    End Sub

    Public Shadows Sub clear()
        innerlist.Clear()
    End Sub

    Public Shadows Sub RemoveAt(ByVal index As Integer)
        innerlist.RemoveAt(index)
    End Sub

End Class